home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / ada / gwuada_5.zip / adaed / nyudemos / maze.ada < prev    next >
Text File  |  1992-09-01  |  8KB  |  260 lines

  1. ----------------------------------------------------------------------
  2. --
  3. --                     Maze Package
  4. --
  5. --                      written by
  6. --
  7. --                   Edmond Schonberg
  8. --
  9. --                      Ada Project
  10. --                   Courant Institute
  11. --                  New York University
  12. --                   251 Mercer Street
  13. --                New York, New York  10012
  14. --
  15. -----------------------------------------------------------------------
  16.  
  17. package maze is
  18.    -- basic data structures.
  19.    type position is record
  20.        row, col: integer ;
  21.    end record ;
  22.  
  23.    type direction is (up, right, down, left) ;
  24.    goal: position ;
  25.  
  26.    -- The array dist is a shared data structure, accessed by all exploring
  27.    -- tasks. A given position p in the maze has been visited by some task if
  28.    --     dist(p.pos, p.col) < max_dist.
  29.    dist: array(1..24, 1..80) of integer ;
  30.    max_dist: integer:= 1000 ;
  31.  
  32.    -- procedures to navigate the maze.
  33.  
  34.    function open(p: position) return boolean ;
  35.    procedure mark(p: position; d: direction) ;
  36.    procedure new_maze(start, goal: position; num_lines: integer) ;
  37.    function next_pos(p: position; d: direction) return position;
  38.    function right_of(d: direction) return direction ;
  39.    function left_of (d: direction) return direction ;
  40.    function back_of (d: direction) return direction ;
  41. end maze ;
  42.  
  43. with maze; use maze;
  44. package first_task is
  45.   type ex ;
  46.   type explore is access ex ;
  47.   task type ex is
  48.      entry start(p: position; d: direction; me, parent: explore) ;
  49.      entry report(success: boolean; where: position) ;
  50.   end ex ;
  51. end first_task ;
  52.  
  53.  
  54. with screen_io; use screen_io;
  55. with system;
  56. package body maze is
  57.  
  58.    function next_pos(p: position; d:direction) return position is
  59.        new_p: position := p;
  60.    begin
  61.       case d is
  62.       when up    => new_p.row := p.row - 1; 
  63.       when right => new_p.col := p.col + 1;
  64.       when down  => new_p.row := p.row + 1; 
  65.       when left  => new_p.col := p.col - 1;
  66.       end case;
  67.       if new_p.row > 23 or new_p.row < 1 or
  68.      new_p.col > 80 or new_p.col < 1 then
  69.      return p ;
  70.       else
  71.      return new_p ;
  72.       end if ;
  73.    end next_pos ;
  74.  
  75.    function right_of(d: direction) return direction is
  76.    begin
  77.        return direction'val((direction'pos(d) + 1)  mod 4 ) ;
  78.    end ;
  79.    function left_of (d: direction) return direction is
  80.    begin
  81.        return direction'val((direction'pos(d) + 3)  mod 4 ) ;
  82.    end ;
  83.  
  84.    function back_of (d: direction) return direction is
  85.    begin
  86.        return direction'val((direction'pos(d) + 2)  mod 4 ) ;
  87.    end ;
  88.  
  89.    function open(p: position) return boolean is
  90.    -- Determine whether a given location has already been explored.
  91.    begin
  92.       return dist(p.row, p.col) = max_dist ;
  93.    end open;
  94.  
  95.    procedure mark(p: position; d: direction) is
  96.    -- Indicate on the screen the current position of an exploring task.
  97.        c: character ;
  98.    begin
  99.        case SYSTEM.SYSTEM_NAME is
  100.        when SYSTEM.PC_DOS => 
  101.            if d = up then c := ASCII.CAN;
  102.            elsif d = down then c := ASCII.EM;
  103.            elsif d = left then c := ASCII.DC1;
  104.            elsif d = right then c := ASCII.DLE;
  105.                end if ;
  106.        when others =>
  107.                   if d = up or d = down then c := '|' ; 
  108.            else c := '-' ; 
  109.            end if ;
  110.        end case; 
  111.        putc(c, p.row, p.col);
  112.    end mark;
  113.  
  114.    procedure new_maze(start, goal: position; num_lines: integer)  is separate ;
  115.  
  116. begin
  117.    -- initialize dist to indicate that all is terra incognita.
  118.    for i in dist'range(1) loop
  119.       for j in dist'range(2) loop
  120.      dist(i, j) := 0 ;
  121.       end loop;
  122.     end loop;
  123. end maze ;
  124.  
  125. with system;
  126. with screen_io; use screen_io;
  127. package body first_task is
  128.     subtype same_ex is ex ;
  129.  
  130.     task census is
  131.         -- keeps track of the number of active exploring tasks.
  132.      entry update(del: integer) ;
  133.     end census ;
  134.  
  135.     task body census is
  136.         population: integer := 1 ;
  137.     begin
  138.      loop
  139.          select
  140.                accept update(del: integer) do
  141.              population := population + del ;
  142.              putsn("active tasks: " , population, 1,1) ;
  143.              end update ;
  144.          or
  145.              terminate ;
  146.             end select ;
  147.         end loop ;
  148.     end census ;
  149.  
  150.     task body ex is
  151.     -- A new exploring task is created whenever an active exploring task
  152.     -- finds an unexplored cell to the right or left of its current pos.
  153.     -- Each such task has a pointer to itself and to its parent. When it
  154.     -- reaches a dead end, it waits for a report from each son, and then
  155.     -- reports in turn to its parent. The first task to read the goal re-
  156.     -- ports success to its parent, and the successful path is retraced.
  157.     
  158.      
  159.     pos, new_pos, start_pos: position ;
  160.         dir: direction ;
  161.         found: boolean := false;
  162.         self, pop: explore ;
  163.         progeny: integer := 0 ;
  164.  
  165.         procedure try_turn(new_dir: direction) is
  166.        -- see if path exists to right or left of current position.
  167.             new_pos: position := next_pos(pos, new_dir) ;
  168.          son: explore;
  169.         begin
  170.         if open(new_pos) then
  171.             -- This test and the corresponding spawn should be a critical
  172.             -- section. As it stands, the program is clearly erroneous,
  173.             -- as  the shared variable -dist-  is being accessed 
  174.             -- without explicit synchronization.
  175.             --  The algorithm works in any case, and the benign rare 
  176.         -- condition here is left to allow for greater parallelism,
  177.         --  at the possible expense of additional (short-lived 
  178.         -- and superflouous) tasks.
  179.  
  180.             son := new same_ex ;
  181.             progeny := progeny + 1 ;
  182.             census.update(1) ;
  183.             son.start(pos, new_dir, son, self) ;
  184.              end if ;
  185.          end try_turn;
  186.  
  187.      procedure retrace(there, here: position) is
  188.          -- mark the path to success, in reverse.
  189.          bck: direction := back_of(dir);
  190.          pos: position := there;
  191.          ch:  character;
  192.     begin
  193.         case SYSTEM.SYSTEM_NAME is
  194.         when SYSTEM.PC_DOS =>
  195.             ch := ASCII.EOT;
  196.         when others =>
  197.             ch := '+';
  198.         end case;
  199.         while pos /= here loop
  200.             putcb(ch, pos.row, pos.col) ;
  201.             pos := next_pos(pos, bck) ;
  202.         end loop ;
  203.     end retrace ;
  204.  
  205.     begin
  206.         -- upon creation, get identity from creator, and current location.
  207.         accept start(p: position; d: direction; me, parent: explore) do
  208.         start_pos := p ;
  209.             pos  := next_pos(p, d) ;
  210.             dir  := d ;
  211.         self := me ;
  212.         pop  := parent ;
  213.         end start ;
  214.  
  215.         putc('O', pos.row, pos.col) ;        -- hatch.
  216.         putc('o', pos.row, pos.col) ;
  217.  
  218.         begin
  219.             loop
  220.             mark(pos, dir) ;
  221.             dist(pos.row, pos.col) := 0 ;        -- we've been here.
  222.                 try_turn(right_of(dir)) ;        -- look both ways.
  223.                 try_turn(left_of(dir)) ;
  224.             new_pos := next_pos(pos, dir) ;    -- and proceed.
  225.             exit when new_pos = goal or not open(new_pos) ;
  226.             pos := new_pos;
  227.             end loop ;
  228.     exception
  229.         when storage_error | program_error =>
  230.         puts("unable to create new tasks. Try simpler maze.", 23,1);
  231.     end ;
  232.  
  233.     if new_pos = goal then
  234.         putc(ascii.bel, goal.row, goal.col);    -- bingo!
  235.         found := true ;
  236.     else
  237.         for i in 1..progeny loop        -- anyone got there?
  238.             accept report(success: boolean; where: position) do
  239.             found := success ;
  240.             pos := where ;
  241.               end report ;
  242.             exit when found ;
  243.         end loop;
  244.     end if ;
  245.     if found then
  246.         retrace(pos, start_pos) ;
  247.     end if ;
  248.     if pop /= self then            -- not true for first task.
  249.         if pop'callable then
  250.             pop.report(found, start_pos) ;
  251.         end if ;
  252.     elsif not found then
  253.         puts("no  way from here to there      ", 23, 1);
  254.     end if ;
  255.  
  256.         census.update(-1) ;            -- exit discretely.
  257.     end ex ;
  258.  
  259.  end first_task;
  260.